$OpenBSD: patch-Ident_pm,v 1.2 2015/09/05 07:25:15 benoit Exp $
--- Ident.pm.orig	Sun Dec 14 08:08:02 2014
+++ Ident.pm	Sat Sep  5 09:14:17 2015
@@ -2,6 +2,7 @@
 
 use strict;
 use Socket;
+use Socket::GetAddrInfo qw( getaddrinfo getnameinfo :constants );
 use Fcntl;
 use FileHandle;
 use Carp;
@@ -50,12 +51,6 @@
     print STDDBG "Debugging turned to level $DEBUG\n";
 }
 
-# protocol number for tcp.
-my $tcpproto = ( getprotobyname('tcp') )[2] || 6;
-
-# get identd port (default to 113).
-my $identport = ( getservbyname( 'ident', 'tcp' ) )[2] || 113;
-
 # what to use to make nonblocking sockets
 my $NONBLOCK = eval "&$Config{o_nonblock}";
 
@@ -146,49 +141,81 @@
     my ( $class, $localaddr, $remoteaddr, $timeout ) = @_;
     my $self = {};
 
-    print STDDBG "Net::Ident::newFromInAddr localaddr=", sub { inet_ntoa( $_[1] ) . ":$_[0]" }
-      ->( sockaddr_in($localaddr) ), ", remoteaddr=", sub { inet_ntoa( $_[1] ) . ":$_[0]" }
-      ->( sockaddr_in($remoteaddr) ), ", timeout=", defined $timeout ? $timeout : "<undef>", "\n"
-      if $DEBUG > 1;
+    if ($DEBUG > 1) {
+       my ($err, $lip, $lport, $rip, $rport);
+       ($err, $lip, $lport) = getnameinfo($localaddr, NI_NUMERICHOST|NI_NUMERICSERV, 0);
+       ($err, $rip, $rport) = getnameinfo($remoteaddr, NI_NUMERICHOST|NI_NUMERICSERV, 0);
+       printf STDDBG "Net::Ident::newFromInAddr localaddr=%s port %s remoteaddr=%s port %s defined timeout=%s\n",
+           $lip, $lport, $rip, $rport, defined $timeout ? $timeout : "<undef>";
+    }
 
     eval {
         # unpack addresses and store in
-        my ( $localip, $remoteip );
-        ( $self->{localport},  $localip )  = sockaddr_in($localaddr);
-        ( $self->{remoteport}, $remoteip ) = sockaddr_in($remoteaddr);
+        my($family, $err, $localip, $remoteip, @res);
+        $family = sockaddr_family($localaddr);
+        if ($family != sockaddr_family($remoteaddr)) {
+            die "= local and remote address family mismatch\n";
+        }
 
-        # create a local binding port. We cannot bind to INADDR_ANY, it has
-        # to be bind (bound?) to the same IP address as the connection we're
-        # interested in on machines with multiple IP addresses
-        my $localbind = sockaddr_in( 0, $localip );
+        ($err, $localip, $self->{localport}) = getnameinfo($localaddr,
+           NI_NUMERICHOST | NI_NUMERICSERV);
+        if ($err) {
+            die "= local getnameinfo failed: $err\n";
+        }
 
+        ($err, $remoteip, $self->{remoteport}) = getnameinfo($remoteaddr,
+            NI_NUMERICHOST | NI_NUMERICSERV);
+        if ($err) {
+            die "= remote getnameinfo failed: $err\n";
+        }
+
         # store max time
         $self->{maxtime} = defined($timeout) ? time + $timeout : undef;
 
-        # create a remote connect point
-        my $identbind = sockaddr_in( $identport, $remoteip );
+        # create a local binding port.
+        ($err, @res) = getaddrinfo($localip, 0, {
+            flags => AI_PASSIVE|AI_NUMERICHOST,
+            family => $family,
+            socktype => SOCK_STREAM
+        });
+        if ($err) {
+            die "= local getaddrinfo failed: $err\n";
+        }
 
-        # create a new FileHandle
-        $self->{fh} = new FileHandle;
+        for my $ai ( @res ) {
+            my $fh = new FileHandle;
+            socket($fh, $ai->{family}, $ai->{socktype}, $ai->{protocol})
+                or next;
 
-        # create a stream socket.
-        socket( $self->{fh}, PF_INET, SOCK_STREAM, $tcpproto )
-          or die "= socket failed: $!\n";
+            # bind it to the same IP number as the local end of THESOCK
+            bind($fh, $ai->{addr})
+                or next;
 
-        # bind it to the same IP number as the local end of THESOCK
-        bind( $self->{fh}, $localbind ) or die "= bind failed: $!\n";
+            # make it a non-blocking socket
+            fcntl($fh, F_SETFL, $NONBLOCK) or die "= fcntl failed: $!\n";
 
-        # make it a non-blocking socket
-        if ( $^O ne 'MSWin32' ) {
-            fcntl( $self->{fh}, F_SETFL, $NONBLOCK ) or die "= fcntl failed: $!\n";
+            $self->{fh} = $fh;
+            last;
         }
+        if (!defined($self->{fh})) {
+            die "= unable to bind to $localaddr: $!\n";
+        }
 
-        # connect it to the remote identd port, this can return EINPROGRESS.
-        # for some reason, reading $! twice doesn't work as it should
-        connect( $self->{fh}, $identbind )
-          or $!{EINPROGRESS}
-          or die "= connect failed: $!\n";
-        $self->{fh}->blocking(0) if $^O eq 'MSWin32';
+        # create a remote connect point
+        ($err, @res) = getaddrinfo($remoteip, 'ident', {
+            flags => AI_NUMERICHOST,
+            family => $family,
+            socktype => SOCK_STREAM
+        });
+        if ($err) {
+            die "= remote getaddrinfo failed: $err\n";
+        }
+
+        for my $ai ( @res ) {
+            connect($self->{fh}, $ai->{addr}) or $!{EINPROGRESS} or
+                die "= connect failed: $!\n";
+            last;
+        }
     };
     if ( $@ =~ /^= (.*)/ ) {
 
@@ -504,10 +531,13 @@
 sub lookupFromInAddr ($$;$) {
     my ( $localaddr, $remoteaddr, $timeout ) = @_;
 
-    print STDDBG "Net::Ident::lookupFromInAddr localaddr=", sub { inet_ntoa( $_[1] ) . ":$_[0]" }
-      ->( sockaddr_in($localaddr) ), ", remoteaddr=", sub { inet_ntoa( $_[1] ) . ":$_[0]" }
-      ->( sockaddr_in($remoteaddr) ), ", timeout=", defined $timeout ? $timeout : "<undef>", "\n"
-      if $DEBUG > 1;
+    if ($DEBUG > 1) {
+        my ($err, $lip, $lport, $rip, $rport);
+        ($err, $lip, $lport) = getnameinfo($localaddr, NI_NUMERICHOST|NI_NUMERICSERV);
+        ($err, $rip, $rport) = getnameinfo($remoteaddr, NI_NUMERICHOST|NI_NUMERICSERV);
+        printf STDDBG "Net::Ident::lookupFromInAddr localaddr=%s port %s, remoteaddr=%s port %s, timeout=%s\n",
+            $lip, $lport, $rip, $rport, defined $timeout ? $timeout : "<undef>";
+    }
 
     Net::Ident->newFromInAddr( $localaddr, $remoteaddr, $timeout )->username;
 }
